package com.hhq.sso.auth.base.filter;

import cn.hutool.core.bean.BeanUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hhq.sso.auth.base.pojo.SystemUserInfo;
import com.hhq.sso.auth.base.util.JwtUtils;
import com.hhq.sso.auth.base.util.SpringContextUtils;
import com.hhq.sso.auth.base.util.SystemUserContext;
import com.hhq.sso.common.api.CommonResult;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;

/**
 * <p>
 * Description: 自定义token验证过滤器，验证成功后将用户信息放入SecurityContext上下文
 * </p>
 *
 * @author : xiaodong.yang
 * @date : 2024/6/20 11:29
 */
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {
    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws IOException {
        try {
            // 获取请求头中的token
            String authorization = request.getHeader("Authorization");
            if (!StringUtils.hasLength(authorization)) {
                // token不存在，交给其他过滤器处理
                filterChain.doFilter(request, response);
                return; // 结束方法
            }

            // 过滤器中无法初始化Bean组件，使用上下文获取
            JwtUtils jwtUtils = SpringContextUtils.getBean("jwtUtils");
            if (jwtUtils == null) {
                throw new RuntimeException();
            }
            String jwtToken = authorization.replace("Bearer ", "");
            // 解析jwt令牌
            Claims claims;
            try {
                claims = jwtUtils.parseJwt(jwtToken);
            } catch (Exception ex) {
                throw new RuntimeException();
            }

            // 获取用户信息
            // 用户名
            String username = (String)claims.get("username");
            // 权限信息
            String authorityString = (String)claims.get("authorityString");
            SystemUserInfo systemUserInfo = BeanUtil.toBean(claims, SystemUserInfo.class);
            systemUserInfo.setToken(jwtToken);
            // 用户信息设置到threadlocal中
            SystemUserContext.setSystemUserInfo(systemUserInfo);
            Collection<? extends GrantedAuthority> authorities = null;

            if (StringUtils.hasText(authorityString)) {
                authorities = Collections.singleton(new SimpleGrantedAuthority(authorityString));
            }
            Authentication authentication = new UsernamePasswordAuthenticationToken(username, null, authorities);

            // 将用户信息放入SecurityContext上下文
            SecurityContextHolder.getContext().setAuthentication(authentication);
            filterChain.doFilter(request, response);
        } catch (Exception ex) {
            // 过滤器中抛出的异常无法被全局异常处理器捕获，直接返回错误结果
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json; charset=utf-8");
            String value = new ObjectMapper().writeValueAsString(CommonResult.fail("用户未登录！"));
            response.getWriter().write(value);
        }
    }
}
